package com.quanyan.platform.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.quanyan.api.APIResponse;
import com.quanyan.api.enums.ApiResponseEnum;
import com.quanyan.club.entity.RespMyLastActivity;
import com.quanyan.club.entity.RespPlaceClubInfo;
import com.quanyan.club.entity.vo.resp.RespSearchActivity;
import com.quanyan.club.service.ClubOpenService;
import com.quanyan.comment.reqeust.ReqUserCollectQuery;
import com.quanyan.comment.serviceFacade.UserCollectServiceFacade;
import com.quanyan.common.constants.Constants;
import com.quanyan.common.utils.GsonUtils;
import com.quanyan.place.entity.PlaceDubboProvider;
import com.quanyan.platform.client.IGatherTagService;
import com.quanyan.platform.constant.PlatformConstants;
import com.quanyan.platform.mapper.*;
import com.quanyan.platform.model.db.*;
import com.quanyan.platform.model.req.ReqNearbyCircleInfo;
import com.quanyan.platform.model.req.ReqRecommendOrNearby;
import com.quanyan.platform.model.resp.*;
import com.quanyan.platform.response.Activity;
import com.quanyan.platform.response.GatherPlaceResponse;
import com.quanyan.platform.response.GatherTagItem;
import com.quanyan.platform.response.RespGatherTags;
import com.quanyan.platform.service.GatherService;
import com.quanyan.platform.service.PlatformRecommendService;
import com.quanyan.platform.thrift.gathering.*;
import com.quanyan.platform.wrapper.IGatheringPlace;
import com.quanyan.redisCluster.config.RedisTemplate;
import com.quanyan.redisCluster.utils.RedisKey;
import org.apache.commons.lang3.StringUtils;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;

/**
 * Created by slong.guo on 2017/3/7.
 */
@Service("iGatherTagService")
public class GatherServiceImpl implements GatherService, IGatherTagService {

    private static final Logger logger = LoggerFactory.getLogger(GatherServiceImpl.class);

    private static final int kSportBasketBall = 1;
    private static final int kSportBadminton = 2;
    private static final int kSportFootball = 3;
    private static final int kSportTennis = 4;

    private static final int kOpRecommend = 1;
    private static final int kOpNearby = 2;

    private static final int kTabStadium = 1;
    private static final int kTabClub = 2;
    private static final int kTabActivity = 3;

    private static final int kRadius = 3000;
    private static final int kRadiusMax = 800000;

    private static final int kStadiumSelf = 1;
    private static final int kStadiumOthers = 2;
    private static final int kStadiumAll = 3;

    private static final int kRecordQuery = 1;
    private static final int kRecordFollow = 2;
    private static final int kRecordAll = 3;

    private static final int kThriftOK = 0;
    private static final int kThriftRetryTimes = 3;

    private static final int kMaxRecommend = 2;

    private static final int kPerPage3 = 3;
    private static final int kPerPage20 = 20;



    private static final int kRecStadiumSubShowNum = 2;
    private static final int kRecClubShowNum = 2;

    private static final String kUserSettingPref = "usersetting_";
    private static final String kGatherSetting = "sportsPosition";

    private static final String kRedisGatherFamily = "kGather";
    private static final String kRedisGatherSportsKey = "keySports";

    @Autowired
    private PlatformRecommendService platformRecommendService;
    @Autowired
    private TbCategoryExtMapper tbCategoryExtMapper;
    @Autowired
    private TbCircleFollowMapper tbCircleFollowMapper;
    @Autowired
    private TbGatherCircleRecordMapper tbGatherCircleRecordMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private IGatheringPlace iGatheringPlace;

    @Autowired
    private UserCollectServiceFacade userCollectServiceFacade;

    @Autowired
    private ClubOpenService clubOpenService;

    @Autowired
    private TbCircleMapper tbCircleMapper;

    @Autowired
    private GatherMapper gatherMapper;


    @Value("${gather.thrift.server.host}")
    private String thriftHost;

    @Value("${gather.thrift.server.port}")
    private int thriftPort;

//    private ObjectPool pool;

    private boolean checkType(int type, int begin, int end) {
        return type >= begin && type <= end;
    }

    private GatheringService.Client getClient() {
        try {
            TTransport transport = new TFramedTransport(new TSocket(thriftHost, thriftPort));
            TProtocol protocol = new TBinaryProtocol(transport);
            transport.open();
            return new GatheringService.Client(protocol);
        } catch (TTransportException e) {
            e.printStackTrace();
            return null;
        }
    }

//    @SuppressWarnings("unchecked")
//    private ObjectPool init(double scavengeRatio) {
//        PoolConfig config = new PoolConfig();
//        config.setPartitionSize(2);
//        config.setMaxSize(20);
//        config.setMinSize(2);
//        config.setMaxIdleMilliseconds(5000);
//        config.setScavengeIntervalMilliseconds(5000);
//        config.setScavengeRatio(scavengeRatio);
//
//        ObjectFactory<GatheringService.Client> factory = new ObjectFactory<GatheringService.Client>() {
//            @Override
//            public GatheringService.Client create() {
//                try {
//
//                    TTransport transport = new TFramedTransport(new TSocket(thriftHost, thriftPort));
//                    TProtocol protocol = new TBinaryProtocol(transport);
//                    transport.open();
//                    return new GatheringService.Client(protocol);
//                } catch (TTransportException e) {
//                    e.printStackTrace();
//                    return null;
//                }
//
//            }
//
//            @Override
//            public void destroy(GatheringService.Client client) {
//
//            }
//
//            @Override
//            public boolean validate(GatheringService.Client client) {
//                return true;
//            }
//        };
//        return new ObjectPool(config, factory);
//    }

//    @PostConstruct
//    private void config() {
//        pool = init(1.0);
//    }

    @Override
    public APIResponse<RespGatherSportCategories> getSports() {

        RedisKey redisKey = new RedisKey(kRedisGatherFamily, kRedisGatherSportsKey);
        RespGatherSportCategories categories = new RespGatherSportCategories();
        List<GatherSportCategoryItem> items = (List<GatherSportCategoryItem>) redisTemplate.get(redisKey);


        if (items != null && !items.isEmpty()) {
            categories.setItems(items);
            return APIResponse.returnSuccess(categories);
        }

        TbCategoryExtExample extExample = new TbCategoryExtExample();
        TbCategoryExtExample.Criteria criteria = extExample.createCriteria();


        criteria.andDisplayEqualTo(1);
        List<TbCategoryExt> categoryExts = tbCategoryExtMapper.selectByExample(extExample);

        items = new ArrayList<>();
        for (TbCategoryExt categoryExt : categoryExts) {
            GatherSportCategoryItem categoryItem = new GatherSportCategoryItem();
            categoryItem.setId(categoryExt.getId());
            categoryItem.setName(categoryExt.getName());
            categoryItem.setComment(categoryExt.getComment());
            categoryItem.setIcon(categoryExt.getIcon());
            categoryItem.setPriority(categoryExt.getPriority());
            categoryItem.setIconUnselect(categoryExt.getIconUnselect());
            items.add(categoryItem);
        }


        categories.setItems(items);
        redisTemplate.set(redisKey, items);

        return APIResponse.returnSuccess(categories);
    }


    private Integer getCircleRadius(int circleID, int sportType) {

        TbCircle circle = getTbCircle(circleID, sportType);
        if (circle == null) {
            return null;
        } else {
            return circle.getRadius();
        }
    }

    private TbCircle getTbCircle(int circleID, int sportType) {
        TbCircleExample example = new TbCircleExample();
        TbCircleExample.Criteria criteria = example.createCriteria();
        criteria.andCircleIdEqualTo(circleID);
        criteria.andCategoryIdEqualTo(sportType);
        criteria.andIsDeleteEqualTo((byte) 0);

        List<TbCircle> circles = tbCircleMapper.selectByExample(example);
        if (circles == null || circles.isEmpty()) {
            return null;
        } else {
            return circles.get(0);
        }
    }

    private int countCircleByCityID(int cityID) {
        TbCircleExample example = new TbCircleExample();
        TbCircleExample.Criteria criteria = example.createCriteria();
        criteria.andCityIdEqualTo(cityID);
        criteria.andIsDeleteEqualTo((byte) 0);

        return tbCircleMapper.countByExample(example);
    }


    @Override
    @SuppressWarnings("unchecked")
    public APIResponse<RespGatherSpots> getCircles(int uid, ReqNearbyCircleInfo req) {

        int cntCity = 0;
        int cityLevel = 0;
        if (req.getCityID() != null && req.getCityID().compareTo(0) > 0) {
            cntCity = countCircleByCityID(req.getCityID());
            cityLevel = cntCity == 0 ? 3 : (cntCity == 1 ? 2 : 1);
        }


        boolean designate = req.getReqType() != null && req.getReqType().equals(1);
        int pageNo = req.getPageNo() == null ? 0 : (designate ? 0 : req.getPageNo());
        int perPage = req.getPerPage() == null ? kPerPage3 : (designate ? kPerPage3 : req.getPerPage());
        int cityID = req.getCityID() == null ? 0 : req.getCityID();

        ReqNearbyCircles reqCircles = new ReqNearbyCircles(
                req.getLongitude(),
                req.getLatitude(),
                req.getSportType(),
                pageNo * perPage,
                perPage,
                uid,
                req.getReqType() != null && req.getReqType().equals(2) ? kRadiusMax : kRadius,
                cityID);
//        Poolable<GatheringService.Client> obj = pool.borrowObject();
//
//        RespCircleInfos respCircleInfos = obj.getObject().getNearbyCircles(reqCircles);
        RespGatherSpots gatherSpots = new RespGatherSpots();
        try {
            GatheringService.Client client = getClient();
            if (client == null) {
                logger.warn("fetch_thrift_client_failed");
                return APIResponse.returnFail(ApiResponseEnum.INTERNAL_ERROR);
            }

            RespCircleInfos respCircleInfos = client.getNearbyCircles(reqCircles);

            logger.info("respCircleInfos_{}", GsonUtils.toJson(respCircleInfos));

            int code = respCircleInfos.getCommon().getCode();
            if (code != kThriftOK) {
                logger.warn("error_in_getting_circles:{}", respCircleInfos);
                return APIResponse.returnFail(code, respCircleInfos.getCommon().getDesc());
            }


            List<GatherSpotItem> circles = new ArrayList<>();
            for (CircleItem circleItem : respCircleInfos.getItems()) {
                circles.add(new GatherSpotItem(circleItem));
            }
            gatherSpots.setCircles(circles);
            gatherSpots.setCityLevel(cityLevel);

            return APIResponse.returnSuccess(gatherSpots);
        } catch (TException e) {
            e.printStackTrace();
            return APIResponse.returnSuccess(gatherSpots);
        }

    }


    private void updateCircleRecord(int uid, CircleItem item) {
        if (uid <= 0 || item == null || StringUtils.isBlank(item.getCircleName())) {
            return;
        }

        TbGatherCircleRecordExample example = new TbGatherCircleRecordExample();
        TbGatherCircleRecordExample.Criteria criteria = example.createCriteria();
        criteria.andUidEqualTo(uid);
        criteria.andCircleIdEqualTo(item.getCircleID());
        criteria.andRecordTypeEqualTo((byte) 1);

        List<TbGatherCircleRecord> records = tbGatherCircleRecordMapper.selectByExample(example);

        Integer allowShow = getUserGatherSettingByUID(uid);
        byte isHide = (allowShow == null || allowShow.equals(1)) ? (byte) 0 : (byte) 1;

        gatherMapper.insertOrUpdateRecord(item.getCircleName(), item.getCircleID(), uid, isHide);


//        TbGatherCircleRecord record = new TbGatherCircleRecord();
//        if (records == null || records.isEmpty()) {
//
//            record.setUid(uid);
//            record.setCircleId(item.getCircleID());
//            record.setStadiumId(0);
//            record.setName(item.getCircleName());
//            record.setRecordType((byte) 1);
//            record.setWeight(1);
//
//            record.setIsHide(isHide);
//
//            record.setIsDelete((byte) 0);
//
//            tbGatherCircleRecordMapper.insertSelective(record);
//        } else {
//            if (records.size() == 1) {
//                record.setName(item.getCircleName());
//                record.setWeight(records.get(0).getWeight() + 1);
//                record.setIsHide(isHide);
//
//                tbGatherCircleRecordMapper.updateByExampleSelective(record, example);
//            }
//        }


    }


    @Override
    public APIResponse<RespGatherCircleRecords> getRecord(int uid, int type) {

        if (type < kRecordQuery || type > kRecordAll) {
            return APIResponse.returnFail(ApiResponseEnum.PARAMETER_INVALID);
        }

        TbGatherCircleRecordExample example = new TbGatherCircleRecordExample();
        TbGatherCircleRecordExample.Criteria criteria = example.createCriteria();

        criteria.andUidEqualTo(uid);
        criteria.andIsDeleteEqualTo((byte) 0);
        example.setOrderByClause("update_time desc");

        if (type != kRecordAll) {
            criteria.andRecordTypeEqualTo((byte) type);
        }

        List<TbGatherCircleRecord> records = tbGatherCircleRecordMapper.selectByExample(example);

        List<GatherCircleRecordItem> queries = new ArrayList<>();
        List<GatherCircleRecordItem> follows = new ArrayList<>();
        for (TbGatherCircleRecord record : records) {
            if (record.getRecordType().equals((byte) kRecordQuery)) {
                queries.add(new GatherCircleRecordItem(record));
            } else {
                follows.add(new GatherCircleRecordItem(record));
            }
        }

        RespGatherCircleRecords circleRecords = new RespGatherCircleRecords();
        circleRecords.setQueries(queries);
        circleRecords.setFollows(follows);

        return APIResponse.returnSuccess(circleRecords);
    }


    @Override
    public APIResponse doFollow(int uid, int circleID) {
        TbCircleFollowExample example = new TbCircleFollowExample();
        TbCircleFollowExample.Criteria criteria = example.createCriteria();

        criteria.andUidEqualTo(uid);
        criteria.andCircleIdEqualTo(circleID);
        List<TbCircleFollow> follows = tbCircleFollowMapper.selectByExample(example);

        TbCircleFollow follow = new TbCircleFollow();
        follow.setUid(uid);
        follow.setCircleId(circleID);
        follow.setUpdateTime(new Date());

        if (follows == null || follows.isEmpty()) {
            follow.setCreateTime(new Date());
            tbCircleFollowMapper.insertSelective(follow);
        } else {
            if (follows.get(0).getFollow() == (byte) 1) {
                follow.setFollow((byte) 0);
            } else {
                follow.setFollow((byte) 1);
            }
            tbCircleFollowMapper.updateByExample(follow, example);
        }

        return APIResponse.returnSuccess();
    }


    @Override
    @SuppressWarnings("unchecked")
    public APIResponse<RespGatherItems> getRecommendOrNearby(int uid, ReqRecommendOrNearby req) {
        int sportType = req.getSportType();
        int tabType = req.getTabType();
        double lat = req.getLatitude();
        double lng = req.getLongitude();
        int circleId = req.getCircleID();
        double circleLat;
        double circleLng;
        int radius;
        if (!checkType(sportType, kSportBasketBall, kSportTennis)
                || !checkType(tabType, kTabStadium, kTabActivity)) {
            return APIResponse.returnFail(ApiResponseEnum.PARAMETER_INVALID);
        }

        GatherSpotItem circleItem = getCircleInfoByID(uid, req.getCircleID(), req.getSportType());

        if (!circleItem.isValid()) {
            logger.warn("circle_item_invalid, uid:{} req_params:circleID:{} sportType:{}", uid, req.getCircleID(), req.getSportType());
        }

        TbCircle circle = getTbCircle(circleId, sportType);
        if (circle == null) {
            return APIResponse.returnFail(ApiResponseEnum.INTERNAL_ERROR);
        } else {
            circleLat = circle.getCenterLat();
            circleLng = circle.getCenterLng();
            radius = circle.getRadius();
        }

        RespGatherItems gatherItems = new RespGatherItems();
        List<RespRecommendItem> recommends = new ArrayList<>();
        List<GatherStadiumItem> stadiumItems = new ArrayList<>();
        List<GatherClubItem> clubItems = new ArrayList<>();
        List<GatherActivityItem> activityItems = new ArrayList<>();

        switch (tabType) {
            case kTabStadium:
                stadiumItems = getNearbyStadiums(uid, req);
                logger.info("req_stadium_rpc_args:circleID:{},sportType:{},uid:{},lat:{},lng:{}",
                        circleId,
                        sportType,
                        uid,
                        lat,
                        lng);
                long stadiumStartTime = System.currentTimeMillis();
                logger.info("开始获取场馆推荐信息--STADIUM：请求参数：circle:{};sportType:{};uid:{};lat:{};lng:{};开始时间：{}",circleId,sportType,uid,lat,lng,stadiumStartTime);
                APIResponse<?> response = iGatheringPlace.findGatheringPlace(
                        circleId,
                        sportType,
                        uid,
                        lat,
                        lng);
                long stadiumEndTime = System.currentTimeMillis();
                logger.info("场馆推荐信息返回结果--STADIUM：{}，返回时间：{}；接口调用时间：{}",GsonUtils.toJson(response),stadiumEndTime,stadiumEndTime - stadiumStartTime);
                if (response == null || !response.isRet()) {
                    logger.warn("error_in_recommending_stadium:{}", response);
                    break;
                }
                logger.info("场馆推荐调用结果：{}",GsonUtils.toJson(response));
                List<GatheringPlaceResponse> resp = (List<GatheringPlaceResponse>) response.getData();
                if (resp == null) {
                    logger.warn("recommend_stadium_response_null:", response);
                    break;
                }
                for (GatheringPlaceResponse placeInfo : resp) {
                    int curCnt = 0;
                    //场馆信息
                    RespPlaceClubInfo placeClubInfo;
                    PlaceDubboProvider placeDubboProvider = placeInfo.getPlaceDubboProvider();
                    RespPlaceClubInfo activityInfo = placeInfo.getRespActivityClubInfo();
                    if (placeDubboProvider == null) {
                        continue;
                    }
                    GatherStadiumItemRecommend gsir = new GatherStadiumItemRecommend(placeDubboProvider);
                    placeClubInfo = placeInfo.getRespPlaceClubInfo();
                    if (placeClubInfo != null) {
                        gsir.setST_clubNum(placeClubInfo.getClubCount());
                    }
                    if (activityInfo != null) {
                        gsir.setST_activityNum(activityInfo.getActivityCount());
                    }
                    recommends.add(new RespRecommendItem(PlatformConstants.kRecStadiumItem, gsir));
                    //场馆视频信息
                    if (placeInfo.getRespPlaceVideoInfo() != null && placeInfo.getRespPlaceVideoInfo().getVideoDetail() != null) {
                        GatherStadiumVideoRecommend videoRecommend = new GatherStadiumVideoRecommend(placeInfo.getRespPlaceVideoInfo());
                        recommends.add(new RespRecommendItem(PlatformConstants.kRecStadiumVideo, videoRecommend));
                        ++curCnt;
                    }
                    if (curCnt >= kRecStadiumSubShowNum) {
                        continue;
                    }
                    //活动
                    if (activityInfo != null && activityInfo.getActivityId() != null && activityInfo.getActivityId().compareTo(0) > 0) {
                        GatherActivityMatchRecommend mr = new GatherActivityMatchRecommend(activityInfo);
                        mr.setAC_addr(placeDubboProvider.getAddress());
                        mr.setAC_distance(placeDubboProvider.getDistance().intValue());
                        if (mr.isValid()) {
                            ++curCnt;
                            recommends.add(new RespRecommendItem(PlatformConstants.kRecStadiumAct, mr));
                        }

                    }
                    if (curCnt >= kRecStadiumSubShowNum) {
                        continue;
                    }
                    //达人
                    GatherPlaceResponse talentsInfo = placeInfo.getGatherPlaceResponse();
                    if (talentsInfo != null && talentsInfo.getPlace_id() != null && talentsInfo.getActivity() != null) {
                        for (Activity activity : talentsInfo.getActivity()) {
                            GatherActivityTalentRecommend talentRecommend = new GatherActivityTalentRecommend();
                            talentRecommend.setAC_talentName(activity.getNick_name());
                            talentRecommend.setAC_talentUid(activity.getUid());
                            talentRecommend.setAC_talentUrl(activity.getHead());
                            talentRecommend.setAC_talentCaption(activity.getBrief());
                            talentRecommend.setAC_talentPerHour(activity.getPrice().intValue());
                            talentRecommend.setAC_talentGender(activity.getGender());
                            talentRecommend.setAC_talentTimeRules(activity.getTime_rule());
                            talentRecommend.setAC_acID(activity.getId());

                            if (placeDubboProvider.getDistance() != null) {
                                talentRecommend.setAC_talentDistance(placeDubboProvider.getDistance().intValue());
                            } else {
                                talentRecommend.setAC_talentDistance(0);
                            }

                            talentRecommend.setAC_talentAddr(placeDubboProvider.getAddress());
                            talentRecommend.setAC_talentTime(0L);
                            talentRecommend.setAC_curTime(System.currentTimeMillis());
                            talentRecommend.setAC_brief(activity.getBrief());
                            talentRecommend.setAC_introduct(activity.getBrief());


                            ++curCnt;
                            recommends.add(new RespRecommendItem(PlatformConstants.kRecStadiumTalent, talentRecommend));
                            if (curCnt >= kRecStadiumSubShowNum) {
                                break;
                            }
                        }
                    }
                    if (curCnt >= kRecStadiumSubShowNum) {
                        continue;
                    }
                    //俱乐部
                    if (placeClubInfo != null && placeClubInfo.getClubId() != null) {
                        GatherClubItemRecommend clubItemRecommend = new GatherClubItemRecommend(placeClubInfo);
                        recommends.add(new RespRecommendItem(PlatformConstants.kRecStadiumClub, clubItemRecommend));
                    }
                }
//                List<GatherStadiumItem> filteredStadiums = new ArrayList<>();
//                for (GatherStadiumItem gatherStadiumItem : stadiumItems.getStadiums()) {
//                    if(!stadiumIDs.contains(gatherStadiumItem.getStadiumID())){
//                        gatherStadiumItem.setFollow(userFollowedStadium(uid, gatherStadiumItem.getStadiumID()));
//                        filteredStadiums.add(gatherStadiumItem);
//                    }
//                }
//                stadiumItems.setStadiums(filteredStadiums);

                break;
            case kTabClub:
                clubItems = getNearbyClubs(uid, req);

                logger.info("req_club_rpc_args:maxrecommend:{},lat:{},lng:{},radius:{},sportType:{},uid:{}",
                        kMaxRecommend,
                        lat,
                        lng,
                        (double) kRadius,
                        sportType,
                        uid);
                long clubStartTime = System.currentTimeMillis();
                logger.info("开始获取俱乐部推荐信息--CLUB：请求参数：circle:{};sportType:{};uid:{};lat:{};lng:{};开始时间：{}",circleId,sportType,uid,lat,lng,clubStartTime);
                List<RespClubRecommendInfo> clubRecommendInfos = platformRecommendService.getClubInfoRecommend(
                        kMaxRecommend,
                        lat,
                        lng,
                        (double) kRadius,
                        sportType,
                        uid,
                        circleId,
                        circleLat,
                        circleLng,
                        radius);
                long clubEndTime = System.currentTimeMillis();
                logger.info("俱乐部推荐信息返回结果--CLUB：{}，返回时间：{}；接口调用时间：{}",GsonUtils.toJson(clubRecommendInfos),clubStartTime,clubEndTime - clubStartTime);
                for (RespClubRecommendInfo clubRecommendInfo : clubRecommendInfos) {
                    if (clubRecommendInfo.getRespClubBaseInfo() != null) {

                        recommends.add(new RespRecommendItem(PlatformConstants.kRecClubItem, clubRecommendInfo.getRespClubBaseInfo()));

                        //推荐的俱乐部即有活动又有动态的时候，只需要外挂活动
                        boolean hasActivity = false;
                        RespSearchActivity respSearchActivity = clubRecommendInfo.getRespSearchActivity();
                        if (respSearchActivity != null && respSearchActivity.getActivityId() != null) {
                            recommends.add(new RespRecommendItem(PlatformConstants.kRecClubAct, respSearchActivity));
                            hasActivity = true;
                        }

                        if (clubRecommendInfo.getRespClubDynamicInfo() != null && !hasActivity) {
                            recommends.add(new RespRecommendItem(PlatformConstants.kRecClubDynamic, clubRecommendInfo.getRespClubDynamicInfo()));
                        }

                    }


                }

                break;
            case kTabActivity:
                activityItems = getNearbyActivities(uid, req);
                logger.info("req_activity_rpc_args:circleID:{},sportType:{},lat:{},lng:{}",
                        circleId,
                        sportType,
                        lat,
                        lng);
                long talentStartTime = System.currentTimeMillis();
                logger.info("开始获取达人推荐信息--TALENT：请求参数：circle:{};sportType:{};uid:{};lat:{};lng:{};开始时间：{}",circleId,sportType,uid,lat,lng,talentStartTime);
                //推荐达人活动
                List<RespTalentActivity> talentActivities = platformRecommendService.getTalentRecommend(
                        circleId,
                        sportType,
                        lat,
                        lng,
                        circleLat,
                        circleLng,
                        radius);
                long talentEndTime = System.currentTimeMillis();
                logger.info("达人活动推荐信息返回结果--TALENT：{}，返回时间：{}；接口调用时间：{}",GsonUtils.toJson(talentActivities),talentEndTime,talentEndTime - talentStartTime);
                if (talentActivities == null || talentActivities.isEmpty()) {
                    logger.warn("recommend_activity_null_or_empty: uid:{} req:{}", uid, req);
                    break;
                }
                for (RespTalentActivity talentActivity : talentActivities) {

                    recommends.add(new RespRecommendItem(PlatformConstants.kRecActivityTalent, talentActivity));

                    if (talentActivity.getRespVideoBaseInfo() != null) {
                        recommends.add(new RespRecommendItem(PlatformConstants.kRecActivityTalentVideo, talentActivity.getRespVideoBaseInfo()));
                    }
                }
                long activityStartTime = System.currentTimeMillis();
                logger.info("开始获取活动推荐信息--ACTIVITY：请求参数：circle:{};sportType:{};uid:{};lat:{};lng:{};开始时间：{}",circleId,sportType,uid,lat,lng,activityStartTime);
                //推荐俱乐部活动
                List<RespSearchActivity> respSearchActivityList = platformRecommendService.getClubActivityRecommend(
                        1,
                        lat,
                        lng,
                        sportType,
                        circleId,
                        circleLat,
                        circleLng,
                        radius);
                long activityEndTime = System.currentTimeMillis();
                logger.info("达人活动推荐信息返回结果--ACTIVITY：{}，返回时间：{}；接口调用时间：{}",GsonUtils.toJson(respSearchActivityList),activityEndTime,activityEndTime - activityStartTime);
                if (!respSearchActivityList.isEmpty()) {
                    for (RespSearchActivity respSearchActivity : respSearchActivityList) {
                        recommends.add(new RespRecommendItem(PlatformConstants.kRecActivityMatch, respSearchActivity));
                    }
                }
                //我的俱乐部活动
                long myClubStartTime = System.currentTimeMillis();
                logger.info("开始获取活动推荐信息--MY：请求参数：circle:{};sportType:{};uid:{};lat:{};lng:{};开始时间：{}",circleId,sportType,uid,lat,lng,myClubStartTime);
                if (uid != 0) {
                    RespMyLastActivity myLastActivity = platformRecommendService.getMyClubActivity(
                            uid,
                            circleLat,
                            circleLng,
                            radius);
                    long myClubEndTime = System.currentTimeMillis();
                    logger.info("达人活动推荐信息返回结果--MY：{}，返回时间：{}；接口调用时间：{}",GsonUtils.toJson(myLastActivity),myClubEndTime,myClubEndTime - myClubStartTime);
                    if (myLastActivity != null) {
                        recommends.add(new RespRecommendItem(PlatformConstants.kRecActivityMyClubAct, myLastActivity));
                    }

                }


                break;
            default:
                return APIResponse.returnFail(ApiResponseEnum.PARAMETER_INVALID);
        }

        gatherItems.setCircleItem(circleItem);
        gatherItems.setTabType(tabType);
        gatherItems.setRecommends(recommends);
        gatherItems.setNearbyStadiums(stadiumItems);
        gatherItems.setNearbyClubs(clubItems);
        gatherItems.setNearbyActivities(activityItems);
        return APIResponse.returnSuccess(gatherItems);
    }


    private List<GatherStadiumItem> getNearbyStadiums(int uid, ReqRecommendOrNearby req) {
        List<GatherStadiumItem> stadiumItems = new ArrayList<>();

        ReqNearbyStadiums reqStadiums = new ReqNearbyStadiums(
                req.getCircleID(),
                req.getSportType(),
                req.getLongitude(),
                req.getLatitude(),
                uid,
                kStadiumAll
        );

        try {
//            Poolable<GatheringService.Client> obj = pool.borrowObject();
//            RespNearbyStadiums respStadiumsNearby = obj.getObject().getNearbyStadiums(reqStadiums);

            GatheringService.Client client = getClient();
            if (client == null) {
                logger.warn("fetch_thrift_client_failed");
                return stadiumItems;
            }

            RespNearbyStadiums respStadiumsNearby = client.getNearbyStadiums(reqStadiums);

            logger.info("respStadiumsNearby_{}", GsonUtils.toJson(respStadiumsNearby));

            int code = respStadiumsNearby.getCommon().getCode();
            if (code != kThriftOK) {
                return stadiumItems;
            }

            for (StadiumItem stadiumItem : respStadiumsNearby.getItems()) {
                GatherStadiumItem item = new GatherStadiumItem(stadiumItem);
                item.setFollow(userFollowedStadium(uid, stadiumItem.getStadiumID()));
                stadiumItems.add(item);
            }
            return stadiumItems;

        } catch (TException e) {
            e.printStackTrace();
            return stadiumItems;
        }
    }

    private int userFollowedStadium(int uid, int stadiumID) {
        try {
            ReqUserCollectQuery reqUserCollect = new ReqUserCollectQuery();
            reqUserCollect.setSystemCode(Constants.PLACE_SYSTEM_CODE);
            reqUserCollect.setBusinessCode(Constants.PLACE_BOOKING_CODE);
            reqUserCollect.setUserId(uid);
            reqUserCollect.setBusinessId(stadiumID);
            APIResponse<Boolean> resp = userCollectServiceFacade.isUserCollect(reqUserCollect);
            if (null != resp && resp.isRet() && null != resp.getData()) {
                return resp.getData() ? 0 : 1;
            } else {
                return 0;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    private GatherSpotItem getCircleInfoByID(int uid, int circleID, int sportType) {
        logger.info("getCircleInfoByID:uid:{},circleID:{},sportType:{}", uid, circleID, sportType);

        GatherSpotItem spotItem = new GatherSpotItem();
        ReqCircleInfoByID circleInfoByID = new ReqCircleInfoByID();
        ReqCircleItem circleItem = new ReqCircleItem();
        circleItem.setCircleID(circleID);
        circleItem.setSportType(sportType);
        circleInfoByID.setUid(uid);
        circleInfoByID.setReqCircle(circleItem);

        TbCircle tbCircle = getTbCircle(circleID, sportType);
        if (tbCircle == null) {
            logger.warn("no circle info found for circleID:{} sportType:{}", circleID, sportType);
            return spotItem;
        }

        try {
            GatheringService.Client client = getClient();
            if (client == null) {
                logger.warn("fetch_thrift_client_failed");
                return spotItem;
            }
            RespCircleInfo respCircleInfo = client.getCircleInfoByID(circleInfoByID);


            if (respCircleInfo == null) {
                logger.warn("error_resp_circle_info_null");
                return spotItem;
            }

            logger.info("respCircleInfo_{}", GsonUtils.toJson(respCircleInfo));

            int code = respCircleInfo.getCommon().getCode();
            if (code != kThriftOK) {
                logger.info("get_circle_by_id_thrift_error:{}", respCircleInfo);
                return spotItem;
            }

            updateCircleRecord(uid, respCircleInfo.getItem());
            spotItem = new GatherSpotItem(respCircleInfo.getItem());
            return spotItem;

        } catch (TException e) {
            e.printStackTrace();
            return spotItem;
        }
    }

    private List<GatherClubItem> getNearbyClubs(int uid, ReqRecommendOrNearby req) {
        List<GatherClubItem> clubItems = new ArrayList<>();

        ReqNearbyClubs reqNearbyClubs = new ReqNearbyClubs(
                req.getCircleID(),
                req.getSportType(),
                req.getLongitude(),
                req.getLatitude(),
                uid
        );

        try {
//           Poolable<GatheringService.Client> obj = pool.borrowObject();
//           RespNearbyClubs respNearbyClubs = obj.getObject().getNearbyClubs(reqNearbyClubs);

            GatheringService.Client client = getClient();
            if (client == null) {
                logger.warn("fetch_thrift_client_failed");
                return clubItems;
            }

            RespNearbyClubs respNearbyClubs = client.getNearbyClubs(reqNearbyClubs);

            logger.info("respNearbyClubs_{}", GsonUtils.toJson(respNearbyClubs));

            int code = respNearbyClubs.getCommon().getCode();
            if (code != kThriftOK) {
                logger.info("club_thrift_code_error:{}", respNearbyClubs);
                return clubItems;
            }

            List<Integer> clubIds = new ArrayList<>();
            for (ClubItem clubItem : respNearbyClubs.getItems()) {
                clubIds.add(clubItem.getClubID());
                clubItems.add(new GatherClubItem(clubItem));
            }

            if (!clubIds.isEmpty()) {
                Map<Integer, List<Integer>> idmap = clubOpenService.queryActivityWeekByClubs(clubIds);
                for (GatherClubItem clubItem : clubItems) {
                    clubItem.setActivityWeekDays(idmap.get(clubItem.getClubId()));
                }
            }


            return clubItems;
        } catch (TException e) {
            e.printStackTrace();
            return clubItems;
        }
    }


    private List<GatherActivityItem> getNearbyActivities(int uid, ReqRecommendOrNearby req) {
        List<GatherActivityItem> activityItems = new ArrayList<>();

        ReqNearbyActivities reqNearbyActivities = new ReqNearbyActivities(
                req.getCircleID(),
                req.getSportType(),
                req.getLongitude(),
                req.getLatitude(),
                uid
        );

        try {
//            Poolable<GatheringService.Client> obj = pool.borrowObject();
//            RespNearbyActivities respNearbyActivities = obj.getObject().getNearbyActivities(reqNearbyActivities);

            GatheringService.Client client = getClient();
            if (client == null) {
                logger.warn("fetch_thrift_client_failed");
                return activityItems;
            }

            RespNearbyActivities respNearbyActivities = client.getNearbyActivities(reqNearbyActivities);

            logger.info("respNearbyActivities_{}", GsonUtils.toJson(respNearbyActivities));

            int code = respNearbyActivities.getCommon().getCode();
            if (code != kThriftOK) {
                return activityItems;
            }
            for (ActivityItem activityItem : respNearbyActivities.getItems()) {
                if (activityItem.getActivityID() > 0) {
                    activityItems.add(new GatherActivityItem(activityItem));
                }
            }
            return activityItems;
        } catch (TException e) {
            e.printStackTrace();
            return activityItems;
        }

    }


    @Override
    public APIResponse<RespGatherTags> getGatherTags(int uid, int otherUid, int type) {

        if (uid != otherUid && type != 1) {
            return APIResponse.returnFail(ApiResponseEnum.PARAMETER_INVALID);
        }

//        Integer allowShow = getUserGatherSettingByUID(otherUid);
//        byte isHide = (allowShow == null || allowShow.equals(1)) ? (byte) 0 : (byte) 1;


        TbGatherCircleRecordExample example = new TbGatherCircleRecordExample();
        TbGatherCircleRecordExample.Criteria criteria = example.createCriteria();

        criteria.andUidEqualTo(otherUid);
        criteria.andIsDeleteEqualTo((byte) 0);
        if (type == 1) {
            criteria.andIsHideEqualTo((byte) 0);
        }

        List<TbGatherCircleRecord> records = tbGatherCircleRecordMapper.selectByExample(example);

        List<GatherTagItem> tagItems = new ArrayList<>();
        for (TbGatherCircleRecord record : records) {
            tagItems.add(new GatherTagItem(record.getId(), record.getName()));
        }

        RespGatherTags gatherTags = new RespGatherTags(tagItems);
        logger.info("gatherTags:{}", GsonUtils.toJson(gatherTags));

        return APIResponse.returnSuccess(new RespGatherTags(tagItems));
    }

    @Override
    public APIResponse editGatherTags(int uid, List<Integer> ids) {
        if (uid <= 0 || ids == null) {
            return APIResponse.returnFail(ApiResponseEnum.PARAMETER_INVALID);
        }

        if (ids.isEmpty()) {
            TbGatherCircleRecord record = new TbGatherCircleRecord();
            record.setIsHide((byte) 1);

            TbGatherCircleRecordExample example = new TbGatherCircleRecordExample();
            TbGatherCircleRecordExample.Criteria criteria = example.createCriteria();
            criteria.andUidEqualTo(uid);

            tbGatherCircleRecordMapper.updateByExampleSelective(record, example);

        } else {
            TbGatherCircleRecordExample example1 = new TbGatherCircleRecordExample();
            TbGatherCircleRecordExample.Criteria criteria1 = example1.createCriteria();
            TbGatherCircleRecord record1 = new TbGatherCircleRecord();
            record1.setIsHide((byte) 0);
            criteria1.andIdIn(ids);
            criteria1.andUidEqualTo(uid);


            tbGatherCircleRecordMapper.updateByExampleSelective(record1, example1);

            TbGatherCircleRecordExample example2 = new TbGatherCircleRecordExample();
            TbGatherCircleRecordExample.Criteria criteria2 = example2.createCriteria();
            TbGatherCircleRecord record2 = new TbGatherCircleRecord();
            record2.setIsHide((byte) 1);
            criteria2.andUidEqualTo(uid);
            criteria2.andIdNotIn(ids);

            tbGatherCircleRecordMapper.updateByExampleSelective(record2, example2);
        }

        return APIResponse.returnSuccess();
    }

    @SuppressWarnings("unchecked")
    private Integer getUserGatherSettingByUID(int uid) {
        RedisKey redisKey = new RedisKey(kUserSettingPref, Integer.toString(uid));
        String jsonStr = redisTemplate.getRaw(redisKey);
        if (jsonStr == null) {
            return null;
        }
        try {
            HashMap<String, Integer> props = (HashMap<String, Integer>) (new ObjectMapper().readValue(jsonStr, HashMap.class));
            if (props == null) {
                return null;
            }

            logger.info("props:{}", GsonUtils.toJson(props));

            return props.get(kGatherSetting);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

}
